package com.example.javaproject;

import java.util.ArrayList;
import java.util.Stack;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Description:
 * <br>Author：java的验证类
 * <br>Time: 2018/10/29 14:32
 */
public class MyClass {

    /**
     * 对象锁
     */
    private final Object synObj = new Object();


    public static void main(String[] args) {

        MyClass m = new MyClass();
//        m.testSynObj();

//        float d1 = 3.23556f;
//        float d2 = 1f;
//        float d3 = 2.0f;
//        float d4 = 0.1f;
//
//        m.test(d1);
//        m.test(d2);
//        m.test(d3);
//        m.test(d4);

//        m.testThreadLocal();


//        m.testForStack();
//        m.testBitOperation();
        m.testDataHelper();
    }


    /**
     * 测试对象锁,wait(),notify()
     */
    public void testSynObj() {

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (synObj) {
                    System.out.println("T1获取到SynObj对象的监视器，开始执行同步块");

                    try {
                        TimeUnit.SECONDS.sleep(20);
                        System.out.println("T1 在调用wait()方法后，挂起了");
                        synObj.wait();
                        System.out.println("T1被T2唤醒后重新获取synObj的对象监视器，继续执行");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    System.out.println("T1 获取到synObj的对象监视器，继续执行");
                }
            }
        });


        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("T2 启动，但是因为T1占用了synObj对象监视器，则等待T1执行sysObj.wait（）释放对象锁");

                synchronized (synObj) {

                    System.out.println("在T1执行synObj.wait（）后，T2获取到synObj对象监视器，进入到同步代码块");

                    synObj.notify();

                    System.out.println("T2执行synObj.notify(),T1被唤醒，但T2还在同步代码块中(T2还持有对象锁)，没有释放对象监视器，T1要等待对象锁");

                    try {
                        TimeUnit.SECONDS.sleep(20);

                        System.out.println("T2同步块执行完成，释放syn对象监视器，T1获取到synObj对象监视器，并执行wait后面的操作");

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

            }
        });


        t1.start();
        t2.start();

    }

    /**
     * 保留2位小数
     *
     * @param v
     */
    public void test(float v) {
//        java.text.DecimalFormat df =new java.text.DecimalFormat("#.00");
//        System.out.println(df.format(v));


        String s = String.format("%.2f", v);
        System.out.println(s);

    }


    /**
     * 对线程池的学习
     */
    public void testThreadPool() {
    }

    /**
     * test ThreadLocal
     */
    public void testThreadLocal() {
        final ThreadLocal<String> mStringThreadLocal = new ThreadLocal<String>() {
            @Override
            protected String initialValue() {
                return "i am threadlocal";
            }
        };

        mStringThreadLocal.set("set 1");
        System.out.println(Thread.currentThread().getName() + "---" + mStringThreadLocal.get());

        new Thread(new Runnable() {
            @Override
            public void run() {
                mStringThreadLocal.set("set 2");
                System.out.println(Thread.currentThread().getName() + "---" + mStringThreadLocal.get());
            }
        }).start();
    }


    private Stack<String> mStack = new Stack<>();


    private void testForStack() {

        new MThread("T1", mStack).start();
        new MThread("T2", mStack).start();

//        mStack.push("a");
//        mStack.push("b");
//        mStack.push("c");
//        mStack.push("d");
//        mStack.push("e");

        synchronized (mStack) {
            mStack.notifyAll();
        }
    }


    class MThread extends Thread {

        private Stack<String> mStack;

        public MThread(String name, Stack<String> mStack) {
            this.setName(name);
            this.mStack = mStack;
        }

        @Override
        public void run() {
            while (!interrupted()) {
                String topItem = "";

                synchronized (mStack) {
                    if (mStack.isEmpty()) {
                        try {
                            mStack.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }


                }
                topItem = mStack.pop();
                System.out.println(getName() + " topItem--" + topItem);

//                try {
//                    Thread.sleep(10);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }

            }
        }
    }

    /**
     * 位运算操作,参考文献 https://blog.csdn.net/hhy107107/article/details/82801780，https://blog.csdn.net/shenhaiwen/article/details/79001039,https://www.imooc.com/qadetail/203090
     */
    private void testBitOperation() {

        // 1、左移( << )
        // 0000 0000 0000 0000 0000 0000 0000 0101 然后左移2位后，低位补0：//
        // 0000 0000 0000 0000 0000 0000 0001 0100 换算成10进制为20
        System.out.println(5 << 2);// 运行结果是20

        //对负数的左移
        //
        System.out.println(-5 << 2);// 运行结果是20

        System.out.println(910 & 0xff);

        //注意这个 & 0xff的作用是取数的 低8位，原因是0xff的二进制表达是1111 1111
        //任意一个数的二进制和1111 1111进行与运算，只会保留这个数的最后8位(低8位)
        //利用Interger.toHexString(int val)进行把一个 数变成16进制字符串的时候，如果数据为byte，那么会自动补齐前面的24位，如果byte为负数那么高位会补1造成错误
        //例子 如下

        byte a = 120;

        System.out.println(Integer.toHexString(a));
        System.out.println(Integer.toHexString(a & 0xff));

        byte b = -120;

        System.out.println(Integer.toHexString(b));
        System.out.println(Integer.toHexString(b & 0xff));

        System.out.println(~-4);

        System.out.println(3 & (~1));


        System.out.print(Integer.toHexString(2 & 0xff));


    }

    private void testTheadPoll() {

    }

    public void testDataHelper() {

        final DataHelper dataHelper = new DataHelper();

        new Thread(new Runnable() {
            @Override
            public void run() {

                for (int i = 0; i < 100; i++) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    dataHelper.addData(i + "");
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(400);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    dataHelper.readData();
                }
            }
        }).start();
    }


    class DataHelper {

        private Object lock = new Object();
        private boolean mFlag = false;
        private ArrayList<String> data = new ArrayList<>();

        private void addData(String s) {
            synchronized (lock) {
                if (mFlag) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                mFlag = true;
                data.add(s);
                System.out.println("添加了" + s);
                mFlag = false;
                lock.notify();
            }
        }

        public ArrayList<String> readData() {

            ArrayList<String> result = null;

            synchronized (lock) {
                if (mFlag) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                mFlag = true;
                result = data;
                mFlag = false;
                lock.notify();
            }

            StringBuffer sb = new StringBuffer();
            for (String s : result) {
                sb.append(s + ",");
            }
            System.out.println(sb.toString());
            return result;
        }
    }

}
